/**
 * 
 */
package cz.cvut.fit.crhonjar.mi.paa.dunedin.manager;

import java.math.BigDecimal;
import java.math.RoundingMode;

import cz.cvut.fit.crhonjar.mi.paa.dunedin.State;
import cz.cvut.fit.crhonjar.mi.paa.dunedin.exception.DunedinException;
import cz.cvut.fit.crhonjar.mi.paa.dunedin.solver.Solver;

/**
 * @author Jarec
 * 
 */
public class ProblemManager {

	private final int id;

	private Solver solver;

	private BigDecimal solvingTime;

	private final State starting;

	public ProblemManager(final int id, final State starting)
			throws DunedinException {
		if (starting == null) {
			throw new IllegalArgumentException(
					"Problem manager called with NULL starting state!");
		}
		this.id = id;
		this.starting = starting;
	}

	public void accept(final Solver solver) {
		if (solver == null) {
			throw new IllegalArgumentException(
					"Cannot solve problem with NULL solver!");
		}
		this.solver = solver;
		solver.initiate(this.starting);
	}

	public int getCountOfBuckets() {
		return this.starting.getCountOfBuckets();
	}

	public int getId() {
		return this.id;
	}

	public String getSolverName() {
		return this.solver.getName();
	}

	/**
	 * @return the solvingTime
	 * @throws IllegalAccessException
	 */
	public BigDecimal getSolvingTime() throws IllegalAccessException {
		if (this.solvingTime == null) {
			throw new IllegalAccessException(
					"Solving time is NULL. Did you called solve()?");
		}
		return this.solvingTime;
	}

	/**
	 * @return the starting
	 */
	public State getStarting() {
		return this.starting;
	}

	public int getSteps() {
		return this.solver.getCountOfBucketOperations();
	}

	public void solve() throws IllegalAccessException, DunedinException {

		final BigDecimal start = new BigDecimal(System.nanoTime())
				.divide(new BigDecimal(1000000));

		this.solver.solve();

		final BigDecimal stop = new BigDecimal(System.nanoTime())
				.divide(new BigDecimal(1000000));
		this.solvingTime = stop.subtract(start).setScale(3,
				RoundingMode.HALF_UP);
	}

	public String solveToString() throws IllegalAccessException {
		return "Problem ID <" + this.getId() + "> solved in <"
				+ this.getSolvingTime() + " ms> with " + this.getSolverName()
				+ " in " + this.getSteps() + " steps visited: "
				+ this.solver.getStatesVisited() + " states!";
	}

}
